package com.sshine.solon.rabbitmq.impl;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.sshine.solon.rabbitmq.RabbitmqException;
import com.sshine.solon.rabbitmq.RabbitmqProps;
import org.noear.solon.Utils;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 通道工厂
 *
 * @author noear
 * @since 1.2
 */
public class RabbitChannelFactory {

    private ConnectionFactory connectionFactory;

    private final ThreadLocal<Channel> channelThreadLocal = new ThreadLocal<>();


    public RabbitChannelFactory() {
        String rabbitmqServer = RabbitmqProps.getRabbitmqServer();

        String host = rabbitmqServer.split(":")[0];
        int port = Integer.parseInt(rabbitmqServer.split(":")[1]);
        String virtualHost = RabbitmqProps.getVirtualhost();

        connectionFactory = new ConnectionFactory();
        // 配置连接信息
        connectionFactory.setHost(host);
        connectionFactory.setPort(port);
        connectionFactory.setRequestedHeartbeat(30);

        String username = RabbitmqProps.getUsername();
        String password = RabbitmqProps.getPassword();
        if (Utils.isNotEmpty(username)) {
            connectionFactory.setUsername(username);
        }
        if (Utils.isNotEmpty(password)) {
            connectionFactory.setPassword(password);
        }
        if (Utils.isNotEmpty(virtualHost)) {
            connectionFactory.setVirtualHost(virtualHost);
        }

        // 网络异常自动连接恢复
        connectionFactory.setAutomaticRecoveryEnabled(true);
        // 每5秒尝试重试连接一次
        connectionFactory.setNetworkRecoveryInterval(5000L);
    }

    public ConnectionFactory getConnectionFactory() {
        return connectionFactory;
    }

    private Connection connection;
    public synchronized Connection getConnection() throws IOException, TimeoutException {
        if (connection == null) {
            connection = connectionFactory.newConnection();
        }
        return connection;
    }

    public Channel getChannel() {
        Channel channel = channelThreadLocal.get();
        if (channel == null) {
            try {
                channel = getConnection().createChannel();
            } catch (IOException e) {
                throw new RabbitmqException("Rabbitmq channel create fail",e);
            } catch (TimeoutException e) {
                throw new RabbitmqException("Rabbitmq channel create fail",e);
            }
            channelThreadLocal.set(channel);
        }
        return channel;
    }

    public void closeChannel(){
        Channel channel = getChannel();
        try {
            channel.close();
        } catch (IOException e) {
            throw new RabbitmqException("Rabbitmq channel close fail",e);
        } catch (TimeoutException e) {
            throw new RabbitmqException("Rabbitmq channel close fail",e);
        }
        channelThreadLocal.remove();
    }

}
